<template>
  <component
    :is="formItemComponent"
    :field="field"
    :rules="rules"
    :designer="designer"
    :parent-list="parentList"
    :design-state="designState"
    :parent-widget="parentWidget"
    :sub-form-row-id="subFormRowId"
    :sub-form-row-index="subFormRowIndex"
    :sub-form-col-index="subFormColIndex"
    :index-of-parent-list="indexOfParentList"
  >
    <el-select
      ref="fieldEditor"
      class="full-width-input"
      v-model="fieldModel"
      :size="widgetSize"
      :loading="loading"
      :disabled="field.options.disabled"
      :clearable="field.options.clearable"
      :filterable="field.options.filterable"
      :allow-create="field.options.allowCreate"
      :default-first-option="allowDefaultFirstOption"
      :automatic-dropdown="field.options.automaticDropdown"
      :multiple="field.options.multiple" :multiple-limit="field.options.multipleLimit"
      :placeholder="field.options.placeholder || i18nt('render.hint.selectPlaceholder')"
      :remote="field.options.remote" :remote-method="remoteMethod"
      @focus="handleFocusCustomEvent" @blur="handleBlurCustomEvent"
      @change="handleChange"
    >
      <el-option
        v-for="item in sOptions"
        :key="item.value"
        :label="item.label"
        :value="item.value"
        :disabled="item.disabled"
      />
    </el-select>
  </component>
</template>

<script>
import FormItemWrapper from './form-item-wrapper'
import FormItemRender from './form-item-render.vue'

import i18n from "@/utils/i18n"
import emitter from '@/utils/emitter'

import XEUtils from 'xe-utils'
import { SelectUtils } from './config/select-utils.js'
import { defAxios as request } from '@/utils/http'
import { transformSelect } from '@/utils/transform-utils'

import fieldMixin from "@/components/form-designer/form-widget/field-widget/fieldMixin";
import { fieldBaseMixin } from './mixins'

import { getBaseDictData } from '@/api/api-setting.js'
import { SelectDataType, SelectDictDataType } from '@/base/pojo/SelectDataType.js'

export default {
  name: "select-widget",
  // 必须固定为FieldWidget，用于接收父级组件的broadcast事件
  componentName: 'FieldWidget',
  mixins: [emitter, fieldMixin, i18n, fieldBaseMixin],
  inject: ['enumsDataPools'],
  props: {
    field: Object,
    designer: Object,
    parentList: Array,
    parentWidget: Object,
    indexOfParentList: Number,
    /** 是否为设计状态 */
    designState: { type: Boolean, default: false },
    /* 子表单组件行索引，从0开始计数 */
    subFormRowIndex: { type: Number, default: -1 },
    /* 子表单组件列索引，从0开始计数 */
    subFormColIndex: { type: Number, default: -1 },
    /* 子表单组件行Id，唯一id且不可变 */
    subFormRowId: { type: String, default: '' },
  },
  components: {
    FormItemRender,
    FormItemWrapper,
  },
  data() {
    return {
      rules: [],
      loading: false,
      sOptions: [],
      showCode: true,
      sNodeMap: {},
      fieldModel: null,
      currentNode: {},
      oldFieldValue: null, //field组件change之前的值
      fristLoaded: true,
    }
  },
  computed: {
    allowDefaultFirstOption() {
      return (!!this.field.options.filterable && !!this.field.options.allowCreate)
    },
    remoteMethod() {
      if (!!this.field.options.remote && !!this.field.options.onRemoteQuery) {
        return this.remoteQuery
      } else {
        return undefined
      }
    },
    filedOptions() {
      return this.field.options
    },
    fieldNames() {
      return this.filedOptions.optionConfig.fieldNames
    },
    formItemComponent() {
      return !!this.designer ? FormItemWrapper : FormItemRender
    }
  },
  beforeCreate() {
    /* 这里不能访问方法和属性！！ */
  },
  created() {
    this.initOptionItems()
    this.initFieldModel()
    this.registerToRefList()
    this.initEventHandler()
    this.buildFieldRules()
    this.handleOnCreated()
  },
  beforeMount() {
    // 加载选框数据
    this.loadOptionsData()
  },
  mounted() {
    this.handleOnMounted()
  },
  beforeUnmount() {
    this.unregisterFromRefList()
  },
  watch: {
    'filedOptions.multiple': {
      handler(newValue, oldValue) {
        if (newValue) {
          this.fieldModel = []
        } else {
          this.fieldModel = null
        }
      }
    },
  },

  methods: {
    /**
     * 加载下拉选框数据
     * 
     * @param condition 条件
     */
    loadOptionsData(condition) {
      // 设计状态不加载
      if (this.designState) return
      // 加载数据
      const { filedOptions } = this
      const { optionConfig, optionItemsSelect } = filedOptions
      const { mode: selectMode, fieldNames } = optionConfig
      // 设置是否显示编码
      if (filedOptions.hasOwnProperty('showCode')) {
        this.showCode = filedOptions.showCode
      } else {
        this.showCode = true
      }
      if (SelectDataType.DICT.equals(selectMode)) {
        this.loadOptionDict(optionConfig.dictConfig, fieldNames, condition)
      } else if (SelectDataType.SERVE.equals(selectMode)) {
        this.loadOptionServe(optionConfig.serveConfig, fieldNames, condition)
      } else if (SelectDataType.STATIC.equals(selectMode)) {
        let optionItems = []
        if (optionItemsSelect && optionItemsSelect.length > 0) {
          optionItems = optionItemsSelect
        } else {
          optionItems = optionConfig.staticConfig ? optionConfig.staticConfig.optionItems : []
        }
        this.loadOptionStatic(optionItems, fieldNames)
      } else {
        this.sOptions = []
      }
    },
    /**
     * 加载静态数据
     * @param {Array} values 目标数据
     * @param {Object} props 替换字段
     */
    loadOptionStatic(values, props) {
      const transfResult = transformSelect.transfData(
        XEUtils.clone(values || [], true),
        { type: 'static', props: props, showCode: this.showCode }
      )
      this.sOptions = transfResult.tranfData
      this.setOtherSelInfo(transfResult)
    },
    /**
     * 加载字典项目数据
     * @param {Object} dictConfig 字典项配置
     * @param {Object} props 字段属性配置
     */
    async loadOptionDict(dictConfig, props, condition) {
      const valid = SelectUtils.checkConfig(dictConfig)
      if (!valid) return
      const { dictType, dictParams } = dictConfig
      if (!dictConfig.dictName) return
      let queryCondition = dictParams
      if (condition) { queryCondition = condition }
      let params = this.parseQueryCondition(queryCondition)
      const { hooks }= this.getBusiConfig()
      if(hooks && hooks.useCryptoHook){
        params = hooks.useCryptoHook().encryptDataByRSA(params)
      }
      let resOptions = []
      // 基础数据
      if (SelectDictDataType.BASE.equals(dictType)) {
        resOptions = await this.getOptionBase(dictConfig, props, params)
      }
      // 枚举数据
      if (SelectDictDataType.ENUMS.equals(dictType)) {
        resOptions = this.getOptionEnum(dictConfig, props, params)
      }
      this.sOptions = resOptions
    },
    /**
     * 加载数据（接口）
     * 
     * @param {Object} serveConfig 自定义请求项配置
     * @param {Object} props 字段属性配置
     * @param {Object} condition 额外条件
     */
    async loadOptionServe(serveConfig, props, condition={}) {
      const valid = SelectUtils.checkConfig(serveConfig)
      if (!valid) return
      let config = {
        url: serveConfig.url,
        method: serveConfig.method
      }
      let resultParams = this.parseQueryCondition(serveConfig.params)
      config[serveConfig.paramsType] = { ...resultParams, ...condition }
      if(config[serveConfig.paramsType].hasOwnProperty('condition')){
        const { hooks }= this.getBusiConfig()
        if(hooks && hooks.useCryptoHook){
          config[serveConfig.paramsType].condition = hooks.useCryptoHook().encryptDataByRSA(config[serveConfig.paramsType].condition)
        }
      }
      const resOptions = await this.getOptionServe(config, props)
      this.sOptions = resOptions
    },
    /**
     * 获取枚举选项数据
     * 
     * @param param 参数
     * @param props 传递参数
     */
    getOptionEnum({ dictName }, props) {
      const { enumsDataPools } = this
      const dictInfo = enumsDataPools ? enumsDataPools[dictName] : null
      let result = []
      // 本地枚举信息存在
      if (dictInfo) {
        let enumOptions = dictInfo.options
        if (enumOptions) {
          enumOptions = JSON.parse(JSON.stringify(enumOptions))
          result = Object.keys(enumOptions).map(key => enumOptions[key])
          const transfResult = transformSelect.transfData(result, {
            type: 'enums', props: props, showCode: this.showCode,
          })
          result = transfResult.tranfData
          this.setOtherSelInfo(transfResult)
        }
      }
      return result
    },
    /**
     * 获取字段选项数据
     * 
     * @param param 参数
     * @param props 传递参数
     */
    getOptionBase({ dictName }, props, params) {
      this.loading = true
      if (XEUtils.isString(params)) {
        params = {
          condition: params
        }
      }
      return new Promise(resolve => {
        getBaseDictData(this.axiosConfig.request, {
          name: dictName,
          ...params,
        }).then(res => {
          const { code, data, msg } = res
          if (code === 200) {
            if (data) {
              const transfResult = transformSelect.transfData(data, {
                type: 'base', props: props, showCode: this.showCode,
              })
              resolve(transfResult.tranfData)
              this.setOtherSelInfo(transfResult)
            } else {
              resolve([])
            }
          } else {
            console.error(msg)
            resolve([])
          }
        }).catch(err => {
          console.error(err)
          resolve([])
        }).finally(() => {
          this.loading = false
        })
      })
    },
    /**
     * 获取请求选项数据
     * 
     * @param config 参数
     * @param props 传递参数
     */
    getOptionServe(config, props) {
      this.loading = true
      const reqAxios = this.axiosConfig.request || request
      return new Promise(resolve => {
        reqAxios(config).then(res => {
          const { code, data, msg } = res
          if (code === 200) {
            if (data) {
              const transfResult = transformSelect.transfData(data, {
                type: 'serve', props: props, showCode: this.showCode,
              })
              resolve(transfResult.tranfData)
              this.setOtherSelInfo(transfResult)
            } else {
              resolve([])
            }
          } else {
            console.error(msg)
            resolve([])
          }
        }).catch(err => {
          console.error(err)
          resolve([])
        }).finally(() => {
          this.loading = false
        })
      })
    },
    /**
     * 设置一些额外的信息
     * @param {Object} param 参数信息
     */
    setOtherSelInfo ({ nodeMap, expandMap }) {
      this.sNodeMap = nodeMap
      // 针对单选的情况
      if (this.fieldModel) {
        this.currentNode = nodeMap[this.fieldModel]
      }
    },
    /**
     * 选中的值发生变化
     * @param {String} value 选中的值
     */
    handleChange(value) {
      this.currentNode = this.sNodeMap[value]
      this.handleChangeEvent(value)
    }
  }
}
</script>

<style lang="scss" scoped>
.full-width-input {
  width: 100% !important;
}
</style>
